package com.berwin.syncer.entry;

import com.alibaba.fastjson.JSONObject;
import com.berwin.syncer.entity.SharedFiles;
import com.berwin.syncer.entity.SharedText;
import com.berwin.syncer.listener.ClipboardListener;
import com.berwin.syncer.listener.FileTransferListener;
import com.berwin.syncer.listener.ServerListener;
import com.berwin.syncer.listener.SocketEventListener;
import com.berwin.syncer.monitor.SystemClipboardMonitor;
import com.berwin.syncer.network.FileServer;
import com.berwin.syncer.network.SessionFile;
import com.berwin.syncer.network.TextServer;
import com.berwin.syncer.network.Session;
import com.berwin.syncer.utils.ClipboardUtility;
import com.berwin.syncer.utils.NotificationCenter;
import com.berwin.syncer.utils.UserDefault;
import com.berwin.syncer.views.ConnectView;
import com.berwin.syncer.views.SettingsView;
import com.berwin.syncer.views.UploadView;

import javax.swing.*;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.Map;

public class Syncer implements SocketEventListener, ClipboardListener, FileTransferListener, ServerListener, SettingsView.OnConfigListener {


    private static final int PORT_TEXT_DEF = 11098;
    private static final int PORT_FILE_DEF = 11099;
    private static final int MAX_CACHE_DEF = 30;
    private static final String DOWNLOAD_PATH_DEF = "./res/downloads";
    private static final int MONITOR_INTERVAL_DEF = 1;

    public static int PORT_TEXT = UserDefault.getInstance().getValueForKey(SettingsView.KEY_PORT_TEXT, PORT_TEXT_DEF);
    public static int PORT_FILE = UserDefault.getInstance().getValueForKey(SettingsView.KEY_PORT_FILE, PORT_FILE_DEF);
    public static int MAX_CACHE_ITEM = UserDefault.getInstance().getValueForKey(SettingsView.KEY_MAX_ITEM, MAX_CACHE_DEF);
    public static String DOWNLOAD_PATH = UserDefault.getInstance().getValueForKey(SettingsView.KEY_DOWNLOAD_DIR, DOWNLOAD_PATH_DEF);
    public static int MONITOR_INTERVAL = UserDefault.getInstance().getValueForKey(SettingsView.KEY_MONITOR_INTERVAL, MONITOR_INTERVAL_DEF);

    private PopupMenu devicePopupMenu;
    private PopupMenu textPopupMenu;
    private PopupMenu filePopupMenu;
    private MenuItem controlItem;
    private MenuItem uploadItem;
    private MenuItem scannerItem;

    private SystemClipboardMonitor monitor;

    private TextServer textServer;
    private FileServer fileTransferServer;
    private UploadView uploadView;

    public static void main(String[] args) {
        new Syncer();
    }

    public Syncer() {
        UserDefault.getInstance();
        this.monitor = new SystemClipboardMonitor(this);
        this.textServer = new TextServer(PORT_TEXT, this.monitor);
        this.fileTransferServer = new FileServer(PORT_FILE);
        this.initTray();
    }

    private void initTray() {
        if (SystemTray.isSupported()) {
            ImageIcon icon = new ImageIcon("res/sync.png");
            Image image = icon.getImage();
            TrayIcon trayIcon = new TrayIcon(image);
            trayIcon.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    super.mouseClicked(e);
                }
            });
            trayIcon.setToolTip("手机/PC同步助手");
            trayIcon.setPopupMenu(this.initPopupMenu());
            SystemTray systemTray = SystemTray.getSystemTray();
            try {
                systemTray.add(trayIcon);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            JOptionPane.showMessageDialog(null, "不支持系统托盘");
        }
    }

    private PopupMenu initPopupMenu() {
        PopupMenu popupMenu = new PopupMenu();
        // 启动/关闭
        controlItem = new MenuItem("启动服务");
        controlItem.setShortcut(new MenuShortcut(KeyEvent.VK_S));
        popupMenu.add(controlItem);
        controlItem.addActionListener(e -> {
            if (this.textServer.isRunning()) {
                this.textServer.stop();
                this.monitor.stop();
                controlItem.setLabel("启动服务");
                this.fileTransferServer.stop();
            } else {
                this.textServer.start(this, this);
                this.fileTransferServer.start(this, this);
                this.monitor.start(MONITOR_INTERVAL);
                controlItem.setLabel("停止服务");
                new ConnectView(this.textServer).setVisible(true);
            }
        });

        //
        scannerItem = new MenuItem("扫码连接");
        scannerItem.setEnabled(false);
        scannerItem.setShortcut(new MenuShortcut(KeyEvent.VK_C));
        popupMenu.add(scannerItem);
        scannerItem.addActionListener(e -> {
            if (this.textServer.isRunning()) {
                new ConnectView(this.textServer).setVisible(true);
            } else {
                JOptionPane.showMessageDialog(null, "请先启动服务");
            }
        });

        // 连接设备
        devicePopupMenu = new PopupMenu("连接设备(0)");
        popupMenu.add(devicePopupMenu);

        popupMenu.addSeparator();

        // 文本
        textPopupMenu = new PopupMenu("文本同步");
        popupMenu.add(textPopupMenu);

        // 文件
        filePopupMenu = new PopupMenu("文件同步");
        popupMenu.add(filePopupMenu);
//        filePopupMenu.add(new MenuItem("/User/berwin/documents/DevKits/build.sh"));
//        filePopupMenu.add(new MenuItem("/User/berwin/documents/DevKits/build.sh"));
//        filePopupMenu.add(new MenuItem("/User/berwin/documents/DevKits/build.sh"));

        uploadItem = new MenuItem("上传文件");
        uploadItem.setEnabled(false);
        uploadItem.setShortcut(new MenuShortcut(KeyEvent.VK_U));
        popupMenu.add(uploadItem);
        uploadItem.addActionListener(e -> this.selectFile());
        // 设置
        popupMenu.addSeparator();
        MenuItem aboutItem = new MenuItem("关于软件");
        aboutItem.setShortcut(new MenuShortcut(KeyEvent.VK_A));
        popupMenu.add(aboutItem);
        aboutItem.addActionListener(e -> {
            String name = "关于软件";
            String version = "1.0.0";
            String content = "Sync 移动/PC端丝滑过渡\r\n@版本: 1.0.0\r\n@作者: 唐博文";
            String txt = name + "(" + version + ")" + "\r\n\r\n" + content;
            JOptionPane.showMessageDialog(null, txt, "",
                    JOptionPane.INFORMATION_MESSAGE);
        });

        MenuItem gitItem = new MenuItem("开源地址");
        gitItem.setShortcut(new MenuShortcut(KeyEvent.VK_G));
        popupMenu.add(gitItem);
        gitItem.addActionListener(e -> {
            String url = "https://gitee.com/berwin/Syncer.git";
            try {
                URI u = URI.create(url);
                Desktop desktop = Desktop.getDesktop();
                if (desktop.isSupported(Desktop.Action.BROWSE)) {
                    desktop.browse(u);
                }
            } catch (MalformedURLException ex) {
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        });

        MenuItem settingsItem = new MenuItem("设置");
        popupMenu.add(settingsItem);
        settingsItem.setShortcut(new MenuShortcut(KeyEvent.VK_P));
        settingsItem.addActionListener(e -> {
            new SettingsView(this).setVisible(true);
        });

        popupMenu.addSeparator();
        // 退出
        MenuItem exitItem = new MenuItem("退出");
        exitItem.setShortcut(new MenuShortcut(KeyEvent.VK_Q));
        popupMenu.add(exitItem);
        exitItem.addActionListener(e -> {
            System.exit(0);
        });

        return popupMenu;
    }

    /**
     * 选择上传文件
     */
    private void selectFile() {
        JFileChooser chooser = new JFileChooser();
        FileSystemView fsv = FileSystemView.getFileSystemView();
        String currentDir = UserDefault.getInstance().getValueForKey("cur_dir", fsv.getHomeDirectory().getAbsolutePath());
        chooser.setCurrentDirectory(new File(currentDir));
        chooser.setDialogTitle("请选择要同步的文件");
        chooser.setApproveButtonText("同步");
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        int result = chooser.showOpenDialog(null);
        if (JFileChooser.APPROVE_OPTION == result) {
            String path = chooser.getSelectedFile().getPath();
            UserDefault.getInstance().setValueForKey("cur_dir", chooser.getSelectedFile().getAbsolutePath());
            this.fileTransferServer.broadcast(path, "server", true);
        }
    }

    private void updateDevices() {
        devicePopupMenu.removeAll();
        Map<String, Session> sessions = this.textServer.getSessions();
        for (Map.Entry<String, Session> entry : sessions.entrySet()) {
            String key = entry.getKey();
            MenuItem deviceItem = new MenuItem(key);
            devicePopupMenu.add(deviceItem);
        }
        devicePopupMenu.setLabel(String.format("连接设备(%d)", devicePopupMenu.getItemCount()));
    }

    private void updateTexts() {
        textPopupMenu.removeAll();
        MenuItem clearItem = new MenuItem("清空所有");
        textPopupMenu.add(clearItem);
        clearItem.addActionListener(e -> {
            textPopupMenu.removeAll();
            this.textServer.getTexts().clear();
            textPopupMenu.setLabel(String.format("文本同步"));
        });
        textPopupMenu.addSeparator();
        java.util.List<SharedText> sharedTexts = this.textServer.getTexts();
        for (int i = 0; i < sharedTexts.size(); i++) {
            SharedText text = sharedTexts.get(i);
            MenuItem item = new MenuItem(text.getContent());
            textPopupMenu.add(item);
            item.addActionListener(e -> {
                this.textServer.getMonitor().setLastClipboard(text.getContent());
                ClipboardUtility.setSysClipboardText(text.getContent());
            });
        }
        textPopupMenu.setLabel(String.format("文本同步(%d)", sharedTexts.size()));
    }

    private void updateFiles() {
        filePopupMenu.removeAll();
        MenuItem clearItem = new MenuItem("清空所有");
        filePopupMenu.add(clearItem);
        clearItem.addActionListener(e -> {
            filePopupMenu.removeAll();
            this.fileTransferServer.getFiles().clear();
            filePopupMenu.setLabel(String.format("文件同步"));
        });
        filePopupMenu.addSeparator();
        java.util.List<SharedFiles> sharedFiles = this.fileTransferServer.getFiles();
        for (int i = 0; i < sharedFiles.size(); i++) {
            SharedFiles text = sharedFiles.get(i);
            System.out.println(text.getName());
            MenuItem item = new MenuItem(text.getName());
            filePopupMenu.add(item);
            item.addActionListener(e -> {
                try {
                    Desktop.getDesktop().open(new File(DOWNLOAD_PATH));
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            });
        }
        filePopupMenu.setLabel(String.format("文件同步(%d)", sharedFiles.size()));
    }

    @Override
    public void onConnect(Session session) {
        // 更新连接设备
        this.updateDevices();
    }

    @Override
    public void onDisconnect(Session session) {
        // 更新连接设备
        this.updateDevices();

    }

    @Override
    public void onMessage(Session session, JSONObject data) {
        int type = data.getInteger("type");
        if (type == Session.MSG_TYPE_SYNC_TEXT) {
            this.updateTexts();
        } else if (type == Session.MSG_TYPE_SYNC_FILE) {
            // 同步文件
            this.updateFiles();
        }
    }

    @Override
    public void onClipboardChanged(String text) {
        JSONObject obj = new JSONObject();
        obj.put("type", Session.MSG_TYPE_SYNC_TEXT);
        obj.put("device", "server");
        obj.put("sender", "server");
        obj.put("content", text);
        this.textServer.broadcast(obj, null, false);
        this.updateTexts();
    }

    @Override
    public void onStart(SessionFile task, String path, String fileName) {
        uploadView = new UploadView(fileName);
        uploadView.setVisible(true);
    }

    @Override
    public void onProgress(SessionFile task, int percent) {
        uploadView.setProgress(percent);
    }

    @Override
    public void onFinished(SessionFile task, String path, String fileName) {
        this.updateFiles();
        NotificationCenter.notify("文件同步完成", fileName);
        if (uploadView != null) {
            uploadView.dispose();
            uploadView = null;
        }
    }

    @Override
    public void onError(SessionFile task, String desc) {
        if (uploadView != null) {
            uploadView.dispose();
            uploadView = null;
        }
    }

    @Override
    public void onStarted(Object server) {
        uploadItem.setEnabled(true);
        scannerItem.setEnabled(true);
    }

    @Override
    public void onStoped(Object server) {
        uploadItem.setEnabled(false);
        scannerItem.setEnabled(false);
        this.updateDevices();
    }

    @Override
    public void onConfigChanged(int portText, int portFile, int maxCache, String downloadDir, int monitorInterval) {
        PORT_TEXT = portText;
        PORT_FILE = portFile;
        MAX_CACHE_ITEM = maxCache;
        DOWNLOAD_PATH = downloadDir;
        MONITOR_INTERVAL = monitorInterval;
        if (this.textServer.isRunning()) {
            this.textServer.stop();
            this.fileTransferServer.stop();
            this.monitor.stop();
            controlItem.setLabel("启动服务");
        }
    }
}

